

#ifndef _BUFFER_H_
#define _BUFFER_H_

#include <string>
#include <vector>

namespace zephyr {

class Buffer {
  public:

    static const size_t k_cheapPerpend = 8;
    static const size_t k_initialSize = 1024;

    explicit Buffer(size_t initialSize = k_initialSize) 
        : m_buffer(k_cheapPerpend + initialSize)
        , m_readIndex(k_cheapPerpend)
        , m_writeIndex(k_cheapPerpend) {}

    /**
     * +----------------+------------+-------------+
     * | k_cheapPerpend |    data    |     idle    |
     * +----------------+------------+-------------+
     *                  readindex    writeindex
     */
    size_t readableBytes() const { return m_writeIndex - m_readIndex; } // 数据区的大小
    size_t writableBytes() const { return m_buffer.size() - m_writeIndex; } // writeindex 后的可写区域
    size_t perpendableBytes() const { return m_readIndex; } // readindex 前的空闲区域

    // 获取可读数据的起始地址
    const char *peek() const { return begin() + m_readIndex; }

    // 减小可读数据区的大小
    void retrieve(size_t len) {
        if (len < readableBytes()) {
            m_readIndex += len;
        } else {
            retrieveAll();
        }
    }

    void retrieveAll() {
        m_writeIndex = k_cheapPerpend;        
        m_readIndex = m_writeIndex;
    }

    // 将长度为len的可读数据转为string并返回
    std::string retrieveAsString(size_t len) {
        std::string result(peek(), len);
        retrieve(len);
        return result;
    }

    std::string retrieveAllAsString() {
        return retrieveAsString(readableBytes());
    }

    // 在向buffer中写入前需要调用这个函数，确保有足够的空间
    void ensureWritableBytes(size_t len) {
        if (writableBytes() < len) {
            makeSpace(len);
        }
    }

    char *beginWrite() { return begin() + m_writeIndex; }
    const char *beginWrite() const { return begin() + m_writeIndex; }

    //  将data中len长度的数据 追加到buffer中
    void append(const char *data, size_t len) {
        ensureWritableBytes(len); // 如果writable 后空间不够 尝试移动待读数据，或进行扩容
        std::copy(data, data + len, beginWrite());
        m_writeIndex += len;
    }

    ssize_t readFd(int fd, int *saveErrno);
    ssize_t writeFd(int fd, int *saveErrno);

  private:
    char *begin() { return &*m_buffer.begin(); }
    const char *begin() const { return &*m_buffer.begin(); }

    void makeSpace(size_t len) {
        /**
         * | k_cheapPerpend | xxxx | data | idle  | xxx 表示已读
         * | k_cheapPerpend | data | idle         |
         */
        // len > writesize + xxx size
        if (writableBytes() /* writesize */ + perpendableBytes() /* k_chep + xxx size */ < len + k_cheapPerpend) {
            m_buffer.resize(m_writeIndex + len);
        } else {
            size_t readale = readableBytes();
            std::copy(begin() + m_readIndex /* start */,
                      begin() + m_writeIndex /* end */,
                      begin() + k_cheapPerpend /* new start */);
            m_readIndex = k_cheapPerpend;
            m_writeIndex = m_readIndex + readale;
        }
    }



  private:
    std::vector<char> m_buffer; // init size 1k
    size_t m_readIndex;
    size_t m_writeIndex;
};

}

#endif // _BUFFER_H_
